﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Granite.Testing;
using System.Diagnostics.Contracts;
using System.ComponentModel;

namespace Granite.Modeling.Tests.Mocks
{
	public class Person : Granite.Modeling.SimpleModelBase
	{
		private string p;
		private string p_2;

		public Person(string p, string p_2)
		{
			// TODO: Complete member initialization
			this.p = p;
			this.p_2 = p_2;
		}


		public string FirstName { get; set; }

		public string FullName { get; set; }

		public bool IsChanged { get; set; }

		public string LastName { get; set; }
	}

	public class Utils
	{
		public static object CaptureState(Person person)
		{
			throw new NotImplementedException();
		}
		public Utils()
		{

		}
	}
	[TestClass]
	public class PersonTest
	{


		[TestMethod]
		public void Person_FirstName_Set()
		{
			var person = new Person("Adam", "Smith");
			var eventAssert = new PropertyChangedEventAssert(person);
			var errorsChangedAssert = new ErrorsChangedEventAssert(person);
			var changeAssert = new ChangeAssert(person);

			Assert.IsFalse(person.IsChanged, "Test setup failed, IsChanged is not false");
			Assert.AreEqual("Adam", person.FirstName, "Test setup failed, FirstName is not Adam");
			Assert.AreEqual("Smith", person.LastName, "Test setup failed, LastName is not Smith");

			person.FirstName = "Bob";

			Assert.AreEqual("Bob", person.FirstName, "FirstName setter failed");
			Assert.AreEqual("Bob Smith", person.FullName, "FullName not updated with FirstName changed");
			Assert.AreEqual(true, person.IsChanged, "IsChanged flag was not set when FirstName changed");
			eventAssert.Expect("IsChanged");
			eventAssert.Expect("FirstName");
			eventAssert.Expect("FullName");
			errorsChangedAssert.ExpectNothing("Expected no ErrorsChanged events");
			changeAssert.AssertOnlyChangesAre("FirstName", "FullName", "IsChanged");
		}


[TestMethod]
public void Person_FirstName_Set_Valid()
{
	Person_FirstName_Set("Bob", false);
}

[TestMethod]
public void Person_FirstName_Set_Empty()
{
	Person_FirstName_Set(String.Empty, true);
}

[TestMethod]
public void Person_FirstName_Set_Null()
{
	Person_FirstName_Set(null, true);
}

public void Person_FirstName_Set(string firstName, bool shouldHaveErrors)
{
	var person = new Person("Adam", "Smith");
	var eventAssert = new PropertyChangedEventAssert(person);
	var errorsChangedAssert = new ErrorsChangedEventAssert(person);
	var changeAssert = new ChangeAssert(person);

	Assert.IsFalse(person.IsChanged, "Test setup failed, IsChanged is not false");
	Assert.AreEqual("Adam", person.FirstName, "Test setup failed, FirstName is not Adam");
	Assert.AreEqual("Smith", person.LastName, "Test setup failed, LastName is not Smith");

	person.FirstName = firstName;

	Assert.AreEqual(firstName, person.FirstName, "FirstName setter failed");
	Assert.AreEqual((firstName + " Smith").Trim(), person.FullName, "FullName not updated with FirstName changed");
	Assert.AreEqual(true, person.IsChanged, "IsChanged flag was not set when FirstName changed");
	eventAssert.Expect("IsChanged");
	eventAssert.Expect("FirstName");
	eventAssert.Expect("FullName");

	if (shouldHaveErrors)
	{
		Assert.IsTrue(person.HasErrors, "HasErrors should have remained false");
		errorsChangedAssert.ExpectCountEquals(1, "Expected an ErrorsChanged event");
		changeAssert.AssertOnlyChangesAre("FirstName", "FullName", "IsChanged", "HasErrors");
	}
	else
	{
		errorsChangedAssert.ExpectNothing("Expected no ErrorsChanged events");
		changeAssert.AssertOnlyChangesAre("FirstName", "FullName", "IsChanged");
	}
}

	}



	public class ErrorsChangedEventAssert : EventAssert<DataErrorsChangedEventArgs>
	{
		readonly Person m_Source;

		/// <summary>
		/// Creates a new INotifyPropertyChanged assertion
		/// </summary>
		/// <param name="source"></param>
		public ErrorsChangedEventAssert(Person source)
			: base(source)
		{
			if (source == null)
				throw new ArgumentNullException("source", "source is null.");
			Contract.EndContractBlock();

			m_Source = source;
			m_Source.ErrorsChanged += SourceEventFired;
		}

	}
}
